package com.broheim.websocket.core.endpoint;

import com.broheim.websocket.core.endpoint.server.AbstractServerWebSocketEndpoint;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.LoaderClassPath;
import javassist.NotFoundException;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.ClassFile;
import javassist.bytecode.ConstPool;
import javassist.bytecode.annotation.Annotation;
import javassist.bytecode.annotation.StringMemberValue;


public class EndpointCreator {

    private static final String VALUE = "value";

    private static final String SERVER_ENDPOINT_CLASS_NAME = "javax.websocket.server.ServerEndpoint";

    private static final String COMPONENT_CLASS_NAME = "org.springframework.stereotype.Component";

    private static final String DYNAMIC_PREFIX_CLASS_NAME = "com.framework.websocket.core.endpoint.Dynamic";

    private static final String WEB_SOCKET_SERVER_ENDPOINT_CLASS_NAME = "WebSocketServerEndpoint";

    public Class<AbstractServerWebSocketEndpoint> createEndpoint(String path) throws NotFoundException, CannotCompileException {
        ClassPool cp = ClassPool.getDefault();
        ClassLoader classLoader = this.getClass().getClassLoader();
        LoaderClassPath classLoaderPath = new LoaderClassPath(classLoader);
        cp.appendClassPath(classLoaderPath);

        CtClass ctClass = cp.makeClass(DYNAMIC_PREFIX_CLASS_NAME + path.replaceAll("/", "") + WEB_SOCKET_SERVER_ENDPOINT_CLASS_NAME);
        CtClass superClass = cp.getCtClass(AbstractServerWebSocketEndpoint.class.getName());
        ctClass.setSuperclass(superClass);

        ClassFile ctFile = ctClass.getClassFile();
        ConstPool constpool = ctFile.getConstPool();
        AnnotationsAttribute annotationsAttribute = new AnnotationsAttribute(constpool, AnnotationsAttribute.visibleTag);
        Annotation serverEndpoint = new Annotation(SERVER_ENDPOINT_CLASS_NAME, constpool);
        serverEndpoint.addMemberValue(VALUE, new StringMemberValue(path, constpool));
        Annotation component = new Annotation(COMPONENT_CLASS_NAME, constpool);
        annotationsAttribute.addAnnotation(serverEndpoint);
        annotationsAttribute.addAnnotation(component);
        ctFile.addAttribute(annotationsAttribute);
        return (Class<AbstractServerWebSocketEndpoint>) ctClass.toClass();
    }

}
